
`include "common_header.verilog"

//  *************************************************************************
//  File : scramble58seedl.v
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Daniel Koehler; Thomas Schrobenhauser
//  info@morethanip.com
//  *************************************************************************
//  Description : 10G Base-R PCS Transmit:
//                Self-synchronizing Scrambler for polynom x58+x39+1 with seed
//                loading capability
// 
//  Note: When loading a seed, the data input must already contain the data
//        that should be processed with this new seed at the same time.
// 
//  Version     : $Id: scramble58seedl.v,v 1.2 2016/07/13 06:56:23 dk Exp $
//  *************************************************************************

module scramble58seedl (
   reset,
   sw_reset,
   clk,
   clk_ena,
   seed_ld,
   seed,
   scrambler_bypass,
   din,
   data_in_type,
   dout,
   data_out_type);

parameter OUT_REGISTER = 1;     // 1: implement output register; 0:combinatorial output (zero latency)

input   reset;                  //  active high reset
input   sw_reset;               //  software, sync reset
input   clk;                    //  clock
input   clk_ena;                //  clock enable
input   scrambler_bypass;       // when scrambler_bypass is TRUE the PCS shall pass 
                                // the unscrambled data from the scrambler input rather than the
                                // scrambled data from the scrambler output. The scrambler shall 
                                // continue to advance normally. 
input   seed_ld;                //  ignores data and load the seed when asserted
input   [57:0] seed;            //  seed value to load
input   [63:0] din;             //  Input data
input   [1:0] data_in_type;     //  Data Block type (10: data / 01: control)
output   [63:0] dout;           //  Scrambled output data
output   [1:0] data_out_type;   //  Data Block type (10: data / 01: control)

wire    [63:0] dout; 
reg     [1:0] data_out_type; 

parameter T1 = 39;      //  tap 1
parameter T2 = 58;      //  tap 2
parameter DW = 64; 

wire    [T2 - 1:0] screg1;      //  scrambler history (former output right to left)
reg     [DW - 1:0] oreg;        //  output data
wire    [DW - 1:0] o;           //  scrambled output

//  register descramble seed and output data
//  --------------------------------------------

always @(posedge reset or posedge clk)
   begin : process_1
   if (reset == 1'b 1)
      begin
      oreg <= {(DW){1'b 0}};
      end
   else
      begin
      if(sw_reset == 1'b 1)
         begin
                oreg <= {(DW){1'b 0}};
         end
      else if (clk_ena == 1'b 1)
         begin
                 if( scrambler_bypass==1'b 1 )
                 begin
                        oreg <= din;
                 end
                 else
                 begin
                        oreg <= o;   
                 end
                        
         end
      end
   end

// Either registered (delayed) output or immediate output.

generate if( OUT_REGISTER == 1 )
begin:goreg
        
        assign dout = oreg;
        
        always @(posedge reset or posedge clk)
        begin
                if (reset == 1'b 1)
                begin
                        data_out_type <= {2{1'b 0}};        //  Data Block type (10: data / 01: control)
                end
                else if( clk_ena == 1'b 1 )
                begin
                        data_out_type <= data_in_type;
                end
        end

end
else
begin:gnoreg
        
        assign dout = ( scrambler_bypass==1'b 1 ) ? din : o;

        always @(data_in_type)
        begin
                data_out_type = data_in_type;
        end
        
end
endgenerate
 

//  Wire Scrambler seed value: numbering is inverse from output data, but no extra register necessary
//  MSB is shifted in last and ends up at the lowest position in the scrambler
//  ---------------------------
// 58
// lp: for i in (T2-1) downto 0 generate
//         screg1(i) <= oreg(DW-1-i);     -- MSB of output is equal to LSB of scrambler
// end generate;
assign screg1[57] = seed_ld == 1'b 0 ? oreg[63 - 57] : seed[57]; 
assign screg1[56] = seed_ld == 1'b 0 ? oreg[63 - 56] : seed[56]; 
assign screg1[55] = seed_ld == 1'b 0 ? oreg[63 - 55] : seed[55]; 
assign screg1[54] = seed_ld == 1'b 0 ? oreg[63 - 54] : seed[54]; 
assign screg1[53] = seed_ld == 1'b 0 ? oreg[63 - 53] : seed[53]; 
assign screg1[52] = seed_ld == 1'b 0 ? oreg[63 - 52] : seed[52]; 
assign screg1[51] = seed_ld == 1'b 0 ? oreg[63 - 51] : seed[51]; 
assign screg1[50] = seed_ld == 1'b 0 ? oreg[63 - 50] : seed[50]; 
assign screg1[49] = seed_ld == 1'b 0 ? oreg[63 - 49] : seed[49]; 
assign screg1[48] = seed_ld == 1'b 0 ? oreg[63 - 48] : seed[48]; 
assign screg1[47] = seed_ld == 1'b 0 ? oreg[63 - 47] : seed[47]; 
assign screg1[46] = seed_ld == 1'b 0 ? oreg[63 - 46] : seed[46]; 
assign screg1[45] = seed_ld == 1'b 0 ? oreg[63 - 45] : seed[45]; 
assign screg1[44] = seed_ld == 1'b 0 ? oreg[63 - 44] : seed[44]; 
assign screg1[43] = seed_ld == 1'b 0 ? oreg[63 - 43] : seed[43]; 
assign screg1[42] = seed_ld == 1'b 0 ? oreg[63 - 42] : seed[42]; 
assign screg1[41] = seed_ld == 1'b 0 ? oreg[63 - 41] : seed[41]; 
assign screg1[40] = seed_ld == 1'b 0 ? oreg[63 - 40] : seed[40]; 
assign screg1[39] = seed_ld == 1'b 0 ? oreg[63 - 39] : seed[39]; 
assign screg1[38] = seed_ld == 1'b 0 ? oreg[63 - 38] : seed[38]; 
assign screg1[37] = seed_ld == 1'b 0 ? oreg[63 - 37] : seed[37]; 
assign screg1[36] = seed_ld == 1'b 0 ? oreg[63 - 36] : seed[36]; 
assign screg1[35] = seed_ld == 1'b 0 ? oreg[63 - 35] : seed[35]; 
assign screg1[34] = seed_ld == 1'b 0 ? oreg[63 - 34] : seed[34]; 
assign screg1[33] = seed_ld == 1'b 0 ? oreg[63 - 33] : seed[33]; 
assign screg1[32] = seed_ld == 1'b 0 ? oreg[63 - 32] : seed[32]; 
assign screg1[31] = seed_ld == 1'b 0 ? oreg[63 - 31] : seed[31]; 
assign screg1[30] = seed_ld == 1'b 0 ? oreg[63 - 30] : seed[30]; 
assign screg1[29] = seed_ld == 1'b 0 ? oreg[63 - 29] : seed[29]; 
assign screg1[28] = seed_ld == 1'b 0 ? oreg[63 - 28] : seed[28]; 
assign screg1[27] = seed_ld == 1'b 0 ? oreg[63 - 27] : seed[27]; 
assign screg1[26] = seed_ld == 1'b 0 ? oreg[63 - 26] : seed[26]; 
assign screg1[25] = seed_ld == 1'b 0 ? oreg[63 - 25] : seed[25]; 
assign screg1[24] = seed_ld == 1'b 0 ? oreg[63 - 24] : seed[24]; 
assign screg1[23] = seed_ld == 1'b 0 ? oreg[63 - 23] : seed[23]; 
assign screg1[22] = seed_ld == 1'b 0 ? oreg[63 - 22] : seed[22]; 
assign screg1[21] = seed_ld == 1'b 0 ? oreg[63 - 21] : seed[21]; 
assign screg1[20] = seed_ld == 1'b 0 ? oreg[63 - 20] : seed[20]; 
assign screg1[19] = seed_ld == 1'b 0 ? oreg[63 - 19] : seed[19]; 
assign screg1[18] = seed_ld == 1'b 0 ? oreg[63 - 18] : seed[18]; 
assign screg1[17] = seed_ld == 1'b 0 ? oreg[63 - 17] : seed[17]; 
assign screg1[16] = seed_ld == 1'b 0 ? oreg[63 - 16] : seed[16]; 
assign screg1[15] = seed_ld == 1'b 0 ? oreg[63 - 15] : seed[15]; 
assign screg1[14] = seed_ld == 1'b 0 ? oreg[63 - 14] : seed[14]; 
assign screg1[13] = seed_ld == 1'b 0 ? oreg[63 - 13] : seed[13]; 
assign screg1[12] = seed_ld == 1'b 0 ? oreg[63 - 12] : seed[12]; 
assign screg1[11] = seed_ld == 1'b 0 ? oreg[63 - 11] : seed[11]; 
assign screg1[10] = seed_ld == 1'b 0 ? oreg[63 - 10] : seed[10]; 
assign screg1[9] = seed_ld == 1'b 0 ? oreg[63 - 9] : seed[9]; 
assign screg1[8] = seed_ld == 1'b 0 ? oreg[63 - 8] : seed[8]; 
assign screg1[7] = seed_ld == 1'b 0 ? oreg[63 - 7] : seed[7]; 
assign screg1[6] = seed_ld == 1'b 0 ? oreg[63 - 6] : seed[6]; 
assign screg1[5] = seed_ld == 1'b 0 ? oreg[63 - 5] : seed[5]; 
assign screg1[4] = seed_ld == 1'b 0 ? oreg[63 - 4] : seed[4]; 
assign screg1[3] = seed_ld == 1'b 0 ? oreg[63 - 3] : seed[3]; 
assign screg1[2] = seed_ld == 1'b 0 ? oreg[63 - 2] : seed[2]; 
assign screg1[1] = seed_ld == 1'b 0 ? oreg[63 - 1] : seed[1]; 
assign screg1[0] = seed_ld == 1'b 0 ? oreg[63 - 0] : seed[0]; 
//  connect scrambler mux
//  ---------------------
// screg <= screg1 when (seed_ld='0') else seed;
//  scramble input data
//  ----------------------
//  00 .. 38: T1=39
//     dat1: for i in 0 to (T1-1) generate
//            o(i) <= screg1(T1-1-i) xor screg1(T2-1-i) xor din(i);
//     end generate;
assign o[0] = screg1[39 - 1 - 0] ^ screg1[58 - 1 - 0] ^ din[0]; 
assign o[1] = screg1[39 - 1 - 1] ^ screg1[58 - 1 - 1] ^ din[1]; 
assign o[2] = screg1[39 - 1 - 2] ^ screg1[58 - 1 - 2] ^ din[2]; 
assign o[3] = screg1[39 - 1 - 3] ^ screg1[58 - 1 - 3] ^ din[3]; 
assign o[4] = screg1[39 - 1 - 4] ^ screg1[58 - 1 - 4] ^ din[4]; 
assign o[5] = screg1[39 - 1 - 5] ^ screg1[58 - 1 - 5] ^ din[5]; 
assign o[6] = screg1[39 - 1 - 6] ^ screg1[58 - 1 - 6] ^ din[6]; 
assign o[7] = screg1[39 - 1 - 7] ^ screg1[58 - 1 - 7] ^ din[7]; 
assign o[8] = screg1[39 - 1 - 8] ^ screg1[58 - 1 - 8] ^ din[8]; 
assign o[9] = screg1[39 - 1 - 9] ^ screg1[58 - 1 - 9] ^ din[9]; 
assign o[10] = screg1[39 - 1 - 10] ^ screg1[58 - 1 - 10] ^ din[10]; 
assign o[11] = screg1[39 - 1 - 11] ^ screg1[58 - 1 - 11] ^ din[11]; 
assign o[12] = screg1[39 - 1 - 12] ^ screg1[58 - 1 - 12] ^ din[12]; 
assign o[13] = screg1[39 - 1 - 13] ^ screg1[58 - 1 - 13] ^ din[13]; 
assign o[14] = screg1[39 - 1 - 14] ^ screg1[58 - 1 - 14] ^ din[14]; 
assign o[15] = screg1[39 - 1 - 15] ^ screg1[58 - 1 - 15] ^ din[15]; 
assign o[16] = screg1[39 - 1 - 16] ^ screg1[58 - 1 - 16] ^ din[16]; 
assign o[17] = screg1[39 - 1 - 17] ^ screg1[58 - 1 - 17] ^ din[17]; 
assign o[18] = screg1[39 - 1 - 18] ^ screg1[58 - 1 - 18] ^ din[18]; 
assign o[19] = screg1[39 - 1 - 19] ^ screg1[58 - 1 - 19] ^ din[19]; 
assign o[20] = screg1[39 - 1 - 20] ^ screg1[58 - 1 - 20] ^ din[20]; 
assign o[21] = screg1[39 - 1 - 21] ^ screg1[58 - 1 - 21] ^ din[21]; 
assign o[22] = screg1[39 - 1 - 22] ^ screg1[58 - 1 - 22] ^ din[22]; 
assign o[23] = screg1[39 - 1 - 23] ^ screg1[58 - 1 - 23] ^ din[23]; 
assign o[24] = screg1[39 - 1 - 24] ^ screg1[58 - 1 - 24] ^ din[24]; 
assign o[25] = screg1[39 - 1 - 25] ^ screg1[58 - 1 - 25] ^ din[25]; 
assign o[26] = screg1[39 - 1 - 26] ^ screg1[58 - 1 - 26] ^ din[26]; 
assign o[27] = screg1[39 - 1 - 27] ^ screg1[58 - 1 - 27] ^ din[27]; 
assign o[28] = screg1[39 - 1 - 28] ^ screg1[58 - 1 - 28] ^ din[28]; 
assign o[29] = screg1[39 - 1 - 29] ^ screg1[58 - 1 - 29] ^ din[29]; 
assign o[30] = screg1[39 - 1 - 30] ^ screg1[58 - 1 - 30] ^ din[30]; 
assign o[31] = screg1[39 - 1 - 31] ^ screg1[58 - 1 - 31] ^ din[31]; 
assign o[32] = screg1[39 - 1 - 32] ^ screg1[58 - 1 - 32] ^ din[32]; 
assign o[33] = screg1[39 - 1 - 33] ^ screg1[58 - 1 - 33] ^ din[33]; 
assign o[34] = screg1[39 - 1 - 34] ^ screg1[58 - 1 - 34] ^ din[34]; 
assign o[35] = screg1[39 - 1 - 35] ^ screg1[58 - 1 - 35] ^ din[35]; 
assign o[36] = screg1[39 - 1 - 36] ^ screg1[58 - 1 - 36] ^ din[36]; 
assign o[37] = screg1[39 - 1 - 37] ^ screg1[58 - 1 - 37] ^ din[37]; 
assign o[38] = screg1[39 - 1 - 38] ^ screg1[58 - 1 - 38] ^ din[38]; 
//  39 .. 57: T2=58
//  dat2: for i in T1 to (T2-1) generate
// o(i) <= o(i-T1) xor screg1(T2-1-i) xor din(i);
//         o(i) <= screg1(T1-1-(i-T1)) xor screg1(T2-1-(i-T1)) xor din(i-T1) xor screg1(T2-1-i) xor din(i);
//  end generate;
assign o[39] = screg1[39 - 1 - (39 - 39)] ^ screg1[58 - 1 - (39 - 39)] ^ din[39 - 39] ^ screg1[58 - 1 - 39] ^ din[39]; 
assign o[40] = screg1[39 - 1 - (40 - 39)] ^ screg1[58 - 1 - (40 - 39)] ^ din[40 - 39] ^ screg1[58 - 1 - 40] ^ din[40]; 
assign o[41] = screg1[39 - 1 - (41 - 39)] ^ screg1[58 - 1 - (41 - 39)] ^ din[41 - 39] ^ screg1[58 - 1 - 41] ^ din[41]; 
assign o[42] = screg1[39 - 1 - (42 - 39)] ^ screg1[58 - 1 - (42 - 39)] ^ din[42 - 39] ^ screg1[58 - 1 - 42] ^ din[42]; 
assign o[43] = screg1[39 - 1 - (43 - 39)] ^ screg1[58 - 1 - (43 - 39)] ^ din[43 - 39] ^ screg1[58 - 1 - 43] ^ din[43]; 
assign o[44] = screg1[39 - 1 - (44 - 39)] ^ screg1[58 - 1 - (44 - 39)] ^ din[44 - 39] ^ screg1[58 - 1 - 44] ^ din[44]; 
assign o[45] = screg1[39 - 1 - (45 - 39)] ^ screg1[58 - 1 - (45 - 39)] ^ din[45 - 39] ^ screg1[58 - 1 - 45] ^ din[45]; 
assign o[46] = screg1[39 - 1 - (46 - 39)] ^ screg1[58 - 1 - (46 - 39)] ^ din[46 - 39] ^ screg1[58 - 1 - 46] ^ din[46]; 
assign o[47] = screg1[39 - 1 - (47 - 39)] ^ screg1[58 - 1 - (47 - 39)] ^ din[47 - 39] ^ screg1[58 - 1 - 47] ^ din[47]; 
assign o[48] = screg1[39 - 1 - (48 - 39)] ^ screg1[58 - 1 - (48 - 39)] ^ din[48 - 39] ^ screg1[58 - 1 - 48] ^ din[48]; 
assign o[49] = screg1[39 - 1 - (49 - 39)] ^ screg1[58 - 1 - (49 - 39)] ^ din[49 - 39] ^ screg1[58 - 1 - 49] ^ din[49]; 
assign o[50] = screg1[39 - 1 - (50 - 39)] ^ screg1[58 - 1 - (50 - 39)] ^ din[50 - 39] ^ screg1[58 - 1 - 50] ^ din[50]; 
assign o[51] = screg1[39 - 1 - (51 - 39)] ^ screg1[58 - 1 - (51 - 39)] ^ din[51 - 39] ^ screg1[58 - 1 - 51] ^ din[51]; 
assign o[52] = screg1[39 - 1 - (52 - 39)] ^ screg1[58 - 1 - (52 - 39)] ^ din[52 - 39] ^ screg1[58 - 1 - 52] ^ din[52]; 
assign o[53] = screg1[39 - 1 - (53 - 39)] ^ screg1[58 - 1 - (53 - 39)] ^ din[53 - 39] ^ screg1[58 - 1 - 53] ^ din[53]; 
assign o[54] = screg1[39 - 1 - (54 - 39)] ^ screg1[58 - 1 - (54 - 39)] ^ din[54 - 39] ^ screg1[58 - 1 - 54] ^ din[54]; 
assign o[55] = screg1[39 - 1 - (55 - 39)] ^ screg1[58 - 1 - (55 - 39)] ^ din[55 - 39] ^ screg1[58 - 1 - 55] ^ din[55]; 
assign o[56] = screg1[39 - 1 - (56 - 39)] ^ screg1[58 - 1 - (56 - 39)] ^ din[56 - 39] ^ screg1[58 - 1 - 56] ^ din[56]; 
assign o[57] = screg1[39 - 1 - (57 - 39)] ^ screg1[58 - 1 - (57 - 39)] ^ din[57 - 39] ^ screg1[58 - 1 - 57] ^ din[57]; 
//  58 .. 63
//    dat3: for i in T2 to (DW-1) generate
// o(i) <= o(i-T2) xor o(i-T1) xor din(i);
//            o(i) <= screg1(T1-1-(i-T2)) xor screg1(T2-1-(i-T2)) xor din(i-T2) xor screg1(T1-1-(i-T1)) xor screg1(T2-1-(i-T1)) xor din(i-T1) xor din(i);
//     end generate;
assign o[58] = screg1[38] ^ screg1[57] ^ din[0] ^ screg1[19] ^ screg1[38] ^ din[19] ^ din[58]; 
assign o[59] = screg1[37] ^ screg1[56] ^ din[1] ^ screg1[18] ^ screg1[37] ^ din[20] ^ din[59]; 
assign o[60] = screg1[36] ^ screg1[55] ^ din[2] ^ screg1[17] ^ screg1[36] ^ din[21] ^ din[60]; 
assign o[61] = screg1[35] ^ screg1[54] ^ din[3] ^ screg1[16] ^ screg1[35] ^ din[22] ^ din[61]; 
assign o[62] = screg1[34] ^ screg1[53] ^ din[4] ^ screg1[15] ^ screg1[34] ^ din[23] ^ din[62]; 
assign o[63] = screg1[33] ^ screg1[52] ^ din[5] ^ screg1[14] ^ screg1[33] ^ din[24] ^ din[63]; 

endmodule // module scramble58seedl

